import wx
import cv2
import numpy as np


class SamplingFrame(wx.Frame):
    def __init__(self):
        super().__init__(None, title="采样与量化(模拟)", size=(800, 600))

        # 初始化变量
        self.original_image = None
        self.processed_image = None
        self.sampling_rate = 10
        self.sampling_method = "均值采样"

        self.create_ui()
        self.Center()

    def create_ui(self):
        # 创建主面板
        panel = wx.Panel(self)
        main_sizer = wx.BoxSizer(wx.VERTICAL)

        # 创建顶部控件栏
        self.create_top_controls(panel, main_sizer)

        # 创建图片显示区域
        self.create_image_panel(panel, main_sizer)

        panel.SetSizer(main_sizer)

    def create_top_controls(self, panel, main_sizer):
        # 顶部控件栏
        top_sizer = wx.BoxSizer(wx.HORIZONTAL)

        # 选择图片按钮
        self.select_btn = wx.Button(panel, label="选择图片")
        self.select_btn.Bind(wx.EVT_BUTTON, self.on_select_image)
        top_sizer.Add(self.select_btn, 0, wx.ALL | wx.CENTER, 5)

        # 采样比率滑块
        top_sizer.Add(wx.StaticText(panel, label="采样比率:"), 0, wx.ALL | wx.CENTER, 5)
        self.sampling_slider = wx.Slider(panel, value=10, minValue=1, maxValue=100,
                                       style=wx.SL_HORIZONTAL | wx.SL_LABELS)
        self.sampling_slider.Bind(wx.EVT_SLIDER, self.on_sampling_rate_change)
        top_sizer.Add(self.sampling_slider, 1, wx.ALL | wx.EXPAND, 5)

        # 采样方式下拉框
        top_sizer.Add(wx.StaticText(panel, label="采样方式:"), 0, wx.ALL | wx.CENTER, 5)
        sampling_methods = ["均值采样", "最大值采样"]
        self.method_choice = wx.Choice(panel, choices=sampling_methods)
        self.method_choice.SetSelection(0)  # 默认选择均值采样
        self.method_choice.Bind(wx.EVT_CHOICE, self.on_method_change)
        top_sizer.Add(self.method_choice, 0, wx.ALL | wx.CENTER, 5)

        main_sizer.Add(top_sizer, 0, wx.ALL | wx.EXPAND, 10)

    def create_image_panel(self, panel, main_sizer):
        # 图片显示区域
        self.image_panel = wx.StaticBitmap(panel)
        main_sizer.Add(self.image_panel, 1, wx.ALL | wx.EXPAND, 10)

        # 默认显示提示文字
        self.show_placeholder()

    def show_placeholder(self):
        # 创建占位图像
        placeholder = wx.Bitmap(400, 300)
        dc = wx.MemoryDC(placeholder)
        dc.SetBackground(wx.Brush(wx.Colour(240, 240, 240)))
        dc.Clear()
        dc.SetTextForeground(wx.Colour(128, 128, 128))
        dc.DrawText("请选择图片", 170, 140)
        dc.SelectObject(wx.NullBitmap)
        self.image_panel.SetBitmap(placeholder)

    def on_select_image(self, event):
        # 文件选择对话框
        wildcard = "图片文件 (*.bmp;*.jpg;*.jpeg;*.png)|*.bmp;*.jpg;*.jpeg;*.png"
        dlg = wx.FileDialog(self, "选择图片", wildcard=wildcard,
                           style=wx.FD_OPEN | wx.FD_FILE_MUST_EXIST)

        if dlg.ShowModal() == wx.ID_OK:
            file_path = dlg.GetPath()
            self.load_image(file_path)

        dlg.Destroy()

    def load_image(self, file_path):
        try:
            # 使用OpenCV加载图片
            self.original_image = cv2.imread(file_path)
            if self.original_image is None:
                wx.MessageBox("无法加载图片文件", "错误", wx.OK | wx.ICON_ERROR)
                return

            # 处理并显示图片
            self.process_and_display_image()

        except Exception as e:
            wx.MessageBox(f"加载图片时发生错误: {str(e)}", "错误", wx.OK | wx.ICON_ERROR)

    def on_sampling_rate_change(self, event):
        self.sampling_rate = self.sampling_slider.GetValue()
        if self.original_image is not None:
            self.process_and_display_image()

    def on_method_change(self, event):
        self.sampling_method = self.method_choice.GetStringSelection()
        if self.original_image is not None:
            self.process_and_display_image()

    def process_and_display_image(self):
        if self.original_image is None:
            return

        # 进行采样处理
        self.processed_image = self.sample_image(
            self.original_image, self.sampling_rate, self.sampling_method
        )

        # 显示处理后的图片
        self.display_image(self.processed_image)

    def sample_image(self, image, sample_rate, method):
        height, width = image.shape[:2]

        # 限制采样率不超过图片最小边
        max_sample_rate = min(height, width)
        actual_sample_rate = min(sample_rate, max_sample_rate)

        # 创建输出图像
        output_image = image.copy()

        # 按采样率处理图像
        for y in range(0, height, actual_sample_rate):
            for x in range(0, width, actual_sample_rate):
                # 确定当前块的边界
                y_end = min(y + actual_sample_rate, height)
                x_end = min(x + actual_sample_rate, width)

                # 提取当前块
                block = image[y:y_end, x:x_end]

                # 根据采样方式计算新像素值
                if method == "均值采样":
                    new_value = np.mean(block, axis=(0, 1)).astype(np.uint8)
                else:  # 最大值采样
                    new_value = np.max(block, axis=(0, 1)).astype(np.uint8)

                # 将新值应用到整个块
                output_image[y:y_end, x:x_end] = new_value

        return output_image

    def display_image(self, image):
        # 将OpenCV图像转换为wxPython bitmap
        height, width = image.shape[:2]

        # 调整图像大小以适应显示区域
        panel_size = self.image_panel.GetSize()
        if panel_size.width > 0 and panel_size.height > 0:
            # 计算缩放比例，保持长宽比
            scale_w = panel_size.width / width
            scale_h = panel_size.height / height
            scale = min(scale_w, scale_h, 1.0)  # 不放大，只缩小

            new_width = int(width * scale)
            new_height = int(height * scale)

            if scale < 1.0:
                image = cv2.resize(image, (new_width, new_height))

        # 转换颜色格式 (BGR -> RGB)
        image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)

        # 转换为wx.Image
        wx_image = wx.Image(image_rgb.shape[1], image_rgb.shape[0], image_rgb)

        # 转换为wx.Bitmap并显示
        bitmap = wx.Bitmap(wx_image)
        self.image_panel.SetBitmap(bitmap)

        # 刷新显示
        self.image_panel.Refresh()